import React, {
  useState,
  useReducer,
  useRef,
  useEffect,
  useCallback,
  memo,
} from "react"

// FAKE API: 模拟异步获取城市数据
const fetchCitiesByCountry = (country) => {
  console.log(`Fetching cities for ${country}...`)
  return new Promise((resolve) => {
    setTimeout(() => {
      const cities = {
        USA: [
          { label: "New York", value: "nyc" },
          { label: "Los Angeles", value: "la" },
        ],
        Canada: [
          { label: "Toronto", value: "toronto" },
          { label: "Vancouver", value: "vancouver" },
        ],
        China: [
          { label: "北京", value: "beijing" },
          { label: "上海", value: "shanghai" },
        ],
      }
      console.log(`Fetched cities:`, cities[country] || [])
      resolve(cities[country] || [])
    }, 500)
  })
}

// =================================================================
// 难点二 & 难点三：强大的 useForm Hook (状态管理 & 性能优化)
// =================================================================
// 这个 Hook 是整个动态表单的核心。
// 它内部使用 useReducer 聚合管理所有状态，解决了 useState 滥用问题。
// 它通过发布-订阅模式，实现了对表单性能的极致优化。

const formReducer = (state, action) => {
  switch (action.type) {
    case "SET_FIELD_VALUE":
      return {
        ...state,
        values: {
          ...state.values,
          ...action.payload,
        },
      }
    case "SET_FIELD_ERROR":
      return {
        ...state,
        errors: {
          ...state.errors,
          ...action.payload,
        },
      }
    case "SET_LOADING":
      return {
        ...state,
        loading: {
          ...state.loading,
          ...action.payload,
        },
      }
    case "RESET_FORM":
      return { values: {}, errors: {}, loading: {} }
    default:
      return state
  }
}

function useForm(initialValues = {}) {
  // 使用 useReducer 管理表单的核心状态
  const [state, dispatch] = useReducer(formReducer, {
    values: initialValues,
    errors: {},
    loading: {},
  })

  // 使用 useRef 存储订阅者，避免不必要的重渲染
  // 这是发布-订阅模式的核心
  const subscribers = useRef(new Map())

  // 订阅函数
  const subscribe = useCallback((fieldName, callback) => {
    if (!subscribers.current.has(fieldName)) {
      subscribers.current.set(fieldName, new Set())
    }
    subscribers.current.get(fieldName).add(callback)

    // 返回一个取消订阅的函数
    return () => {
      subscribers.current.get(fieldName).delete(callback)
    }
  }, [])

  // 发布函数
  const publish = useCallback((fieldName, ...args) => {
    if (subscribers.current.has(fieldName)) {
      subscribers.current
        .get(fieldName)
        .forEach((callback) => callback(...args))
    }
  }, [])

  // 更新字段值，并发布通知
  const setFieldValue = useCallback(
    (name, value) => {
      dispatch({ type: "SET_FIELD_VALUE", payload: { [name]: value } })
      publish(name, value)
    },
    [publish]
  )

  // 获取字段值
  const getFieldValue = useCallback(
    (name) => state.values[name],
    [state.values]
  )

  // 验证所有字段
  const validate = useCallback(
    async (schema) => {
      const allErrors = {}
      let isValid = true

      for (const field of schema) {
        const { name, rules = [] } = field
        const value = state.values[name]
        let error = ""

        for (const rule of rules) {
          if (
            rule.required &&
            (value === undefined ||
              value === "" ||
              (Array.isArray(value) && value.length === 0))
          ) {
            error = rule.message
            break
          }
          if (rule.validator) {
            try {
              await rule.validator(value)
            } catch (e) {
              error = e.message
              break
            }
          }
        }

        allErrors[name] = error
        publish(`${name}.error`, error)
        if (error) isValid = false
      }

      dispatch({ type: "SET_FIELD_ERROR", payload: allErrors })
      return { isValid, values: state.values }
    },
    [state.values, publish]
  )

  // 设置加载状态
  const setLoading = useCallback(
    (name, isLoading) => {
      dispatch({ type: "SET_LOADING", payload: { [name]: isLoading } })
      publish(`${name}.loading`, isLoading)
    },
    [publish]
  )

  // 返回一个稳定的 API 对象
  return {
    state,
    setFieldValue,
    getFieldValue,
    subscribe,
    validate,
    setLoading,
  }
}

// =================================================================
// 性能优化的关键：订阅字段状态的自定义 Hook
// =================================================================
function useFormField(form, name) {
  // 订阅 value, error, 和 loading 状态
  const [value, setValue] = useState(() => form.getFieldValue(name))
  const [error, setError] = useState("")
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    const unsubscribeValue = form.subscribe(name, setValue)
    const unsubscribeError = form.subscribe(`${name}.error`, setError)
    const unsubscribeLoading = form.subscribe(`${name}.loading`, setLoading)

    // 组件卸载时取消订阅
    return () => {
      unsubscribeValue()
      unsubscribeError()
      unsubscribeLoading()
    }
  }, [form, name])

  return { value, error, loading }
}

// =================================================================
// 难点一的解决方案：动态字段渲染组件 (DynamicField)
// =================================================================
const DynamicField = memo(({ field, form }) => {
  const {
    name,
    type,
    label,
    placeholder,
    options,
    dependencies = [],
    render,
  } = field

  // 使用 useFormField 订阅特定字段的状态，避免不必要的重渲染
  const { value, error, loading } = useFormField(form, name)
  const dependencyValues = dependencies.map(
    (dep) => useFormField(form, dep).value
  )

  const [dynamicOptions, setDynamicOptions] = useState(options || [])

  // 副作用处理 (例如：数据联动)
  useEffect(() => {
    // 处理依赖项变化
    if (name === "city" && dependencies.includes("country")) {
      const countryValue = form.getFieldValue("country")
      if (countryValue) {
        form.setLoading(name, true)
        fetchCitiesByCountry(countryValue).then((cities) => {
          setDynamicOptions(cities)
          // 当依赖项变化时，通常会清空当前字段的值
          const currentCity = form.getFieldValue(name)
          const isCurrentCityValid = cities.some((c) => c.value === currentCity)
          if (!isCurrentCityValid) {
            form.setFieldValue(name, "")
          }
          form.setLoading(name, false)
        })
      } else {
        setDynamicOptions([])
        form.setFieldValue(name, "")
      }
    }
  }, [dependencyValues[0]]) // 简单起见，这里只监听第一个依赖项

  const handleChange = (e) => {
    form.setFieldValue(name, e.target.value)
  }

  const renderField = () => {
    // 如果提供了 render 函数，则使用它，这提供了最高的灵活性
    if (render) {
      return render(form)
    }

    switch (type) {
      case "input":
      case "password":
        return (
          <input
            type={type}
            value={value || ""}
            onChange={handleChange}
            placeholder={placeholder}
            className="w-full p-2 border rounded-md"
          />
        )
      case "select":
        return (
          <div className="relative">
            <select
              value={value || ""}
              onChange={handleChange}
              className="w-full p-2 border rounded-md appearance-none"
            >
              <option value="" disabled>
                {placeholder || "请选择"}
              </option>
              {dynamicOptions.map((opt) => (
                <option key={opt.value} value={opt.value}>
                  {opt.label}
                </option>
              ))}
            </select>
            {loading && (
              <div className="absolute top-1/2 right-8 -translate-y-1/2 w-4 h-4 border-2 border-gray-400 border-t-transparent rounded-full animate-spin"></div>
            )}
          </div>
        )
      default:
        return <p className="text-red-500">不支持的字段类型: {type}</p>
    }
  }

  // 根据依赖项决定是否渲染此字段
  if (name === "city" && !form.getFieldValue("country")) {
    return null // 如果没有选择国家，则不显示城市选择框
  }

  return (
    <div className="mb-4">
      <label className="block text-sm font-medium text-gray-700 mb-1">
        {label}
      </label>
      {renderField()}
      {error && <p className="text-red-500 text-xs mt-1">{error}</p>}
    </div>
  )
})

// =================================================================
// 动态表单主组件 (DynamicForm)
// =================================================================
function DynamicForm({ schema, form }) {
  const handleSubmit = async (e) => {
    e.preventDefault()
    const { isValid, values } = await form.validate(schema)
    if (isValid) {
      alert("表单验证通过!\n" + JSON.stringify(values, null, 2))
    } else {
      console.log("表单验证失败")
    }
  }

  return (
    <form
      onSubmit={handleSubmit}
      className="p-6 bg-white rounded-lg shadow-md w-full max-w-lg mx-auto"
    >
      {schema.map((field) => (
        <DynamicField key={field.name} field={field} form={form} />
      ))}
      <button
        type="submit"
        className="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded-md transition-colors"
      >
        提交
      </button>
    </form>
  )
}

// =================================================================
// 应用主组件 (App) - 展示如何使用 DynamicForm
// =================================================================
export default function App() {
  const form = useForm({ username: "默认用户" })

  // 难点一：定义灵活的 JSON Schema
  const formSchema = [
    {
      name: "username",
      label: "用户名",
      type: "input",
      placeholder: "请输入用户名",
      rules: [
        { required: true, message: "用户名不能为空" },
        {
          validator: async (value) => {
            if (value === "admin") {
              // 模拟异步校验
              return new Promise((_, reject) =>
                setTimeout(() => reject(new Error('用户名不能为 "admin"')), 500)
              )
            }
          },
        },
      ],
    },
    {
      name: "password",
      label: "密码",
      type: "password",
      placeholder: "请输入密码",
      rules: [{ required: true, message: "密码不能为空" }],
    },
    {
      name: "country",
      label: "国家",
      type: "select",
      placeholder: "请选择国家",
      options: [
        { label: "美国", value: "USA" },
        { label: "加拿大", value: "Canada" },
        { label: "中国", value: "China" },
      ],
      rules: [{ required: true, message: "请选择国家" }],
    },
    {
      name: "city",
      label: "城市",
      type: "select",
      placeholder: "请先选择国家",
      dependencies: ["country"], // 声明依赖于 'country' 字段
      rules: [{ required: true, message: "请选择城市" }],
    },
    {
      name: "customGreeting",
      label: "自定义渲染",
      render: (form) => {
        // 使用订阅钩子获取依赖值
        const { value: username } = useFormField(form, "username")
        return (      
          <div className="p-3 bg-gray-100 rounded-md text-center text-gray-600">
            你好,{" "}
            <span className="font-semibold text-blue-600">
              {username || "游客"}
            </span>
            ! 这是一个自定义渲染组件。
          </div>
        )
      },
    },
  ]

  return (
    <div className="bg-gray-50 min-h-screen flex flex-col items-center justify-center font-sans p-4">
      <div className="w-full max-w-lg">
        <h1 className="text-3xl font-bold text-center mb-2 text-gray-800">
          动态表单 (DynamicForm)
        </h1>
        <p className="text-center text-gray-500 mb-6">
          一个由 JSON Schema 驱动的高性能 React 表单
        </p>
        <DynamicForm schema={formSchema} form={form} />
      </div>
      <div className="w-full max-w-lg mt-6 p-4 bg-white rounded-lg shadow-md">
        <h2 className="text-lg font-semibold mb-2">
          实时表单状态 (来自 useForm)
        </h2>
        <pre className="bg-gray-800 text-white p-4 rounded-md text-sm overflow-x-auto">
          {JSON.stringify(form.state, null, 2)}
        </pre>
      </div>

    </div>
  )
}